import random
from Tkinter import *
import threading
import math

class Aquarium(object):
    def __init__(self):
        self.profondeur = 600
        self.longueur = 1000
        self.largeur = 200
        self.nbPoissons = 150
        self.poissons = self.initPoissons()
        self.oeufs = []
        self.planctons = []
        self.maxPoissons = 400
        
        
    ##############LOOP CONTROLE#################
    def tic(self):
        for i in self.poissons:
            threading.Thread(group=None,target=i.tic).run()
        for i in self.oeufs:
            i.tic()
        for i in self.planctons:
            i.tic()
        self.checkOeufs()
        self.checkPoissons()
        self.checkPlanctons()
        self.spawnPlancton()
        

    ##############VERIFICATIONS#################
    def spawnPlancton(self):
        choix = random.randrange(100)
        if choix == 0:
            self.planctons.append(Plancton(self))
    def checkPlanctons(self):
        for i in self.planctons:
            if i.grosseur <= 0:
                for poisson in self.poissons:
                    if i == poisson.bouffe:
                        poisson.bouffe = None
                self.planctons.remove(i)
    
    def checkOeufs(self):
        for i in self.oeufs:
            if i.age > 300:
                self.oeufs.remove(i)
                
    def checkPoissons(self):
        for i in self.poissons:
            if i.vie <= 0:
                for poisson in self.poissons:
                    if poisson.partenaire == i:
                        poisson.partenaire = None
                    if i in poisson.menaces:
                        poisson.menaces.remove(i)
                print "mort", i.couleur
                self.poissons.remove(i)
    
    ##############INITIALISATION#############
    def initPoissons(self):
        poissons = []
        for i in range(self.nbPoissons):
            poissons.append(Poisson(self, 0, 0, 0, 0))
        return poissons
    

        
class Plancton(object):
    def __init__(self, bocal):
        self.bocal = bocal
        self.x = random.randrange(bocal.longueur)
        self.y = random.randrange(bocal.profondeur)
        self.z = random.randrange(bocal.largeur)
        self.grosseur = 1
        
    def grossir(self):
        self.grosseur += 0.0001*self.grosseur
        
    def tic(self):
        self.grossir()

class Poisson(object):
    def __init__(self, bocal, couleur, x, y, z, niveau=1):
        self.bocal = bocal
        self.couleur=self.choisirCouleur(couleur)
        self.initPosition(x, y, z)
        self.direction=self.initDirection()
        self.niveau = niveau
        self.energie = 10*niveau+2000
        self.vie = 10*niveau+200
        self.frayage = 0
        self.peur = 0
        
        self.predateur = None
        self.menaces = []
        self.partenaire = None
        self.bouffe = None
        self.proie = None
        
    ###########LOOP CONTROLE#################
    def tic(self):
        self.consommerEnergie()
        self.verifierProximite()
        self.avoirPeur()
        self.checkDirection()
        self.bouger()
        self.manger()
        self.combat()
        self.frayage+=1
    
    
    ###########FONCTIONS D'ACTIONS###########
    def combat(self):
        if self.proie:
            if self.x == self.proie.x and self.y == self.proie.y and self.z == self.proie.z:
                self.proie.vie-=self.niveau
                self.energie-=1
            else:
                self.peur = 40
                self.proie = None
    def avoirPeur(self):
        if self.peur > 1:
            self.bouger()
            self.peur -=1
        elif self.peur == 1:
            self.peur = 0
            self.proie = self.predateur
            self.predateur = None
            
    def checkDirection(self):
        if self.proie:
            self.directionCombat()
        elif self.bouffe:
            self.directionPlancton()
        elif self.menaces:
            self.directionMenace()
        elif self.partenaire:
            self.directionFrayer()
        else:
            self.errer()
            
    def manger(self):
        if self.bouffe:
            if self.bouffe.x == self.x and self.bouffe.y == self.y and self.bouffe.z == self.z:
                if self.bouffe.grosseur > 0:
                    self.bouffe.grosseur -= 1
                    self.energie += 200
                    self.vie += 0.2
                    print self.couleur, "a", self.x,self.y,self.z, "mange"
    
    def consommerEnergie(self):
        if self.energie>0:
            self.energie -= 1
            
    def verifierProximite(self):
        self.menaces = []
        for i in self.bocal.poissons:
            if i <> self:
                distance = math.sqrt(math.pow(self.x-i.x,2)+math.pow(self.y-i.y,2)+math.pow(self.z-i.z,2))
                if distance < self.niveau*10+20:
                    if self.couleur == i.couleur and i.frayage>700:
                        self.partenaire = i
                    elif self.vie > i.vie and self.niveau >= i.niveau:
                        self.proie = i
                if i.proie == self and self.peur == 0 and self.proie == None:
                    self.peur = 40
                    self.predateur = i
                    
                        
        for i in self.bocal.planctons:
            distance = math.sqrt(math.pow(self.x-i.x,2)+math.pow(self.y-i.y,2)+math.pow(self.z-i.z,2))
            if distance < self.niveau*10+50:
                if self.bouffe:
                    distBouffe = math.sqrt(math.pow(self.x-self.bouffe.x,2)+math.pow(self.y-self.bouffe.y,2)+math.pow(self.z-self.bouffe.z,2))
                    if distance < distBouffe:
                        self.bouffe = i
                else:
                    self.bouffe = i
                        
    
    def directionCombat(self):
        if self.proie.x > self.x:
            self.direction["longueur"] = 1
        elif self.proie.x < self.x:
            self.direction["longueur"] = -1
        else:
            self.direction["longueur"] = 0
            
        if self.proie.y > self.y:
            self.direction["profondeur"] = 1
        elif self.proie.y < self.y:
            self.direction["profondeur"] = -1
        else:
            self.direction["profondeur"] = 0
            
        if self.proie.z > self.z:
            self.direction["largeur"] = 1
        elif self.proie.z < self.z:
            self.direction["largeur"] = -1
        else:
            self.direction["largeur"] = 0
        
    def directionPlancton(self):
        if self.bouffe.x > self.x:
            self.direction["longueur"] = 1
        elif self.bouffe.x < self.x:
            self.direction["longueur"] = -1
        else:
            self.direction["longueur"] = 0
            
        if self.bouffe.y > self.y:
            self.direction["profondeur"] = 1
        elif self.bouffe.y < self.y:
            self.direction["profondeur"] = -1
        else:
            self.direction["profondeur"] = 0
            
        if self.bouffe.z > self.z:
            self.direction["largeur"] = 1
        elif self.bouffe.z < self.z:
            self.direction["largeur"] = -1
        else:
            self.direction["largeur"] = 0
    
    def directionMenace(self):
        mauvaisesDirectionsX = []
        mauvaisesDirectionsY = []
        mauvaisesDirectionsZ = []
        bonnesX = []
        bonnesY = []
        bonnesZ = []
        for i in self.menaces:
            if self.x < i.x:
                mauvaisesDirectionsX.append(1)
            elif self.x > i.x:
                mauvaisesDirectionsX.append(-1)
            else:
                mauvaisesDirectionsX.append(0)
                
            if self.y < i.y:
                mauvaisesDirectionsY.append(1)
            elif self.y > i.y:
                mauvaisesDirectionsY.append(-1)
            else:
                mauvaisesDirectionsY.append(0)
                
            if self.z < i.z:
                mauvaisesDirectionsZ.append(1)
            elif self.z > i.z:
                mauvaisesDirectionsZ.append(-1)
            else:
                mauvaisesDirectionsZ.append(0)
                
        if -1 not in mauvaisesDirectionsX:
            bonnesX.append(-1)
        if 1 not in mauvaisesDirectionsX:
            bonnesX.append(1)
        if 0 not in mauvaisesDirectionsX:
            bonnesX.append(0)
            
        if -1 not in mauvaisesDirectionsY:
            bonnesY.append(-1)
        if 1 not in mauvaisesDirectionsY:
            bonnesY.append(1)
        if 0 not in mauvaisesDirectionsY:
            bonnesY.append(0)
            
        if -1 not in mauvaisesDirectionsZ:
            bonnesZ.append(-1)
        if 1 not in mauvaisesDirectionsZ:
            bonnesZ.append(1)
        if 0 not in mauvaisesDirectionsZ:
            bonnesZ.append(0)
            
        if (len(bonnesX)) == 0:
            self.direction["longueur"]=random.randrange(3)-1
        else:
            self.direction["longueur"]=bonnesX[random.randrange(len(bonnesX))]
            
        if (len(bonnesY)) == 0:
            self.direction["profondeur"]=random.randrange(3)-1
        else:
            self.direction["profondeur"]=bonnesY[random.randrange(len(bonnesY))]
            
        if (len(bonnesZ)) == 0:
            self.direction["largeur"]=random.randrange(3)-1
        else:
            self.direction["largeur"]=bonnesZ[random.randrange(len(bonnesZ))]
        
    def directionFrayer(self):
        if self.partenaire.x > self.x:
            self.direction["longueur"] = 1
        elif self.partenaire.x < self.x:
            self.direction["longueur"] = -1
        else:
            self.direction["longueur"] = 0
            
        if self.partenaire.y > self.y:
            self.direction["profondeur"] = 1
        elif self.partenaire.y < self.y:
            self.direction["profondeur"] = -1
        else:
            self.direction["profondeur"] = 0
            
        if self.partenaire.z > self.z:
            self.direction["largeur"] = 1
        elif self.partenaire.z < self.z:
            self.direction["largeur"] = -1
        else:
            self.direction["largeur"] = 0
            
            
    
    def pondre(self):
        if self.bocal.maxPoissons > len(self.bocal.poissons):
            print "ponte: "+self.couleur
            oeuf = Oeuf(self.bocal, self.couleur, self.x, self.y, self.z)
            self.bocal.oeufs.append(oeuf)
        else:
            print "frayage impossible", self.couleur
        self.frayage=0
        self.partenaire.frayage = 0
        self.partenaire.partenaire = 0
        self.partenaire = None

    def bouger(self):
        if self.x + self.direction["longueur"] < self.bocal.longueur and self.x + self.direction["longueur"]>0:
            self.x += self.direction["longueur"]
        if self.y + self.direction["profondeur"] < self.bocal.longueur and self.y + self.direction["profondeur"]>0:
            self.y += self.direction["profondeur"]
        if self.z + self.direction["largeur"] < self.bocal.longueur and self.z + self.direction["largeur"]>0:
            self.z += self.direction["largeur"]
            
        if self.partenaire:
            if self.x == self.partenaire.x and self.y == self.partenaire.y and self.z == self.partenaire.z:
                self.pondre()
            
    def errer(self):
        for i in self.direction:
            choix = random.randrange(15)
            if choix == 0:
                if self.direction[i] == -1:
                    self.direction[i] = 0
                elif self.direction[i] == 1:
                    self.direction[i] = 0
                else:
                    yo = random.randrange(2)
                    if yo == 1:
                        self.direction[i] = 1
                    else:
                        self.direction[i] = -1
            
            
    ##########FONCTIONS D'INITIALISATION#########
    def initPosition(self, x, y, z):
        if x==0:
            x=random.randrange(self.bocal.longueur)
        if y==0:
            y=random.randrange(self.bocal.profondeur)
        if z==0:
            z=random.randrange(self.bocal.largeur)
        self.x = x
        self.y = y
        self.z = z
        
    def choisirCouleur(self, couleur):
        if couleur == 0:
            liste=["white","black","blue","red","yellow","green"]
            choix=random.randrange(6)
            return liste[choix]
        else:
            return couleur

    def initDirection(self):
        direction={}
        x=random.randrange(3)-1
        y=random.randrange(3)-1
        z=random.randrange(3)-1
        direction["longueur"]=x
        direction["largeur"]=z
        direction["profondeur"]=y
        return direction
        
class Oeuf(object):
    def __init__(self, bocal, couleur, x, y, z):
        self.bocal = bocal
        self.couleur = couleur
        self.x = x
        self.y = y
        self.z = z
        self.age = 0
        
    def tic(self):
        self.age+=1
        if self.y < self.bocal.profondeur-15:
            self.tomber()
        if self.age>300:
            self.eclore()
        
    def tomber(self):
        self.x += random.randrange(3)-1
        self.z += random.randrange(3)-1
        if self.x<0:
            self.x+=3
        elif self.x>self.bocal.longueur:
            self.x-=3
        self.y += 3
        
    def eclore(self):
        self.bocal.poissons.append(Poisson(self.bocal, self.couleur, self.x, self.y, self.z))
    
class Vue(object):
    def __init__(self, parent, largeur, hauteur):
        self.parent=parent
        self.root=Tk()
        self.frame=Frame(self.root)
        self.canvas=Canvas(self.frame,height=hauteur,width=largeur,bg="aquamarine2")
        self.frame.pack()
        self.bouton=Button(self.frame, text="Remplir", command=self.remplir)
        self.bouton.pack()
        
    def remplir(self):
        self.bouton.destroy()
        self.canvas.pack()
        self.parent.tic()
        
    def afficherPoissons(self, poissons, oeufs, planctons):
        for i in poissons:
            coords = [(i.x,i.y),(i.x,i.y+5+i.z/20),(i.x+10+(i.z/20), i.y+3+(i.z/20))]
            self.canvas.create_polygon(coords, fill=i.couleur)
        for i in planctons:
            self.canvas.create_rectangle(i.x,i.y,i.x+i.grosseur+(i.z/30),i.y+i.grosseur+(i.z/30), fill="gray")
        for i in oeufs:
            self.canvas.create_oval(i.x,i.y,i.x+(i.z/20)+3,i.y+(i.z/20)+3, fill = i.couleur)
            
    def effacer(self):
        self.canvas.delete(ALL)
        
class Controleur(object):
    def __init__(self):
        self.bocal = Aquarium()
        self.vue = Vue(self, self.bocal.longueur, self.bocal.profondeur)
        self.vue.root.mainloop()
        
    def tic(self):
        self.bocal.tic()
        self.vue.effacer()
        self.vue.afficherPoissons(self.bocal.poissons, self.bocal.oeufs, self.bocal.planctons)
        threading.Timer(0.1,self.tic).start()
        
Controleur()